#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
统一日志记录系统
提供标准化的日志配置和管理功能
"""

import os
import sys
import json
import logging
import logging.handlers
import glob
import time
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, Any, Optional, List
from enum import Enum


class LogLevel(Enum):
    """日志级别枚举"""
    DEBUG = logging.DEBUG
    INFO = logging.INFO
    WARNING = logging.WARNING
    ERROR = logging.ERROR
    CRITICAL = logging.CRITICAL


class LogFormat(Enum):
    """日志格式枚举"""
    SIMPLE = "%(asctime)s - %(levelname)s - %(message)s"
    DETAILED = "%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s"
    JSON = "json"
    EMOJI = "%(asctime)s - %(emoji)s %(levelname)s - %(message)s"


class UnifiedLogger:
    """统一日志记录器"""
    
    # Emoji映射
    EMOJI_MAP = {
        'DEBUG': '🔍',
        'INFO': 'ℹ️',
        'WARNING': '⚠️',
        'ERROR': '❌',
        'CRITICAL': '🚨'
    }
    
    def __init__(self, 
                 name: str = "privilege_ma",
                 log_level: LogLevel = LogLevel.INFO,
                 log_format: LogFormat = LogFormat.DETAILED,
                 log_dir: Optional[str] = None,
                 enable_console: bool = True,
                 enable_file: bool = True,
                 enable_rotation: bool = True,
                 max_bytes: int = 10 * 1024 * 1024,  # 10MB
                 backup_count: int = 5,
                 session_id: Optional[str] = None):
        """
        初始化统一日志记录器
        
        Args:
            name: 日志记录器名称
            log_level: 日志级别
            log_format: 日志格式
            log_dir: 日志目录
            enable_console: 是否启用控制台输出
            enable_file: 是否启用文件输出
            enable_rotation: 是否启用日志轮转
            max_bytes: 最大文件大小
            backup_count: 备份文件数量
            session_id: 会话ID
        """
        self.name = name
        self.log_level = log_level
        self.log_format = log_format
        self.log_dir = Path(log_dir) if log_dir else Path("/tmp/privilege_ma_logs")
        self.enable_console = enable_console
        self.enable_file = enable_file
        self.enable_rotation = enable_rotation
        self.max_bytes = max_bytes
        self.backup_count = backup_count
        self.session_id = session_id or datetime.now().strftime('%Y%m%d_%H%M%S')
        
        # 创建日志目录
        self.log_dir.mkdir(parents=True, exist_ok=True)
        
        # 初始化日志记录器
        self.logger = self._setup_logger()
        
    def _setup_logger(self) -> logging.Logger:
        """设置日志记录器"""
        logger = logging.getLogger(self.name)
        logger.setLevel(self.log_level.value)
        
        # 清除现有处理器
        logger.handlers.clear()
        
        # 设置格式器
        formatter = self._get_formatter()
        
        # 添加控制台处理器
        if self.enable_console:
            console_handler = logging.StreamHandler(sys.stdout)
            console_handler.setFormatter(formatter)
            logger.addHandler(console_handler)
        
        # 添加文件处理器
        if self.enable_file:
            log_file = self.log_dir / f"{self.name}_{self.session_id}.log"
            
            if self.enable_rotation:
                file_handler = logging.handlers.RotatingFileHandler(
                    log_file,
                    maxBytes=self.max_bytes,
                    backupCount=self.backup_count,
                    encoding='utf-8'
                )
            else:
                file_handler = logging.FileHandler(log_file, encoding='utf-8')
            
            file_handler.setFormatter(formatter)
            logger.addHandler(file_handler)
        
        return logger
    
    def _get_formatter(self) -> logging.Formatter:
        """获取格式器"""
        if self.log_format == LogFormat.JSON:
            return JsonFormatter()
        elif self.log_format == LogFormat.EMOJI:
            return EmojiFormatter()
        else:
            return logging.Formatter(
                self.log_format.value,
                datefmt='%Y-%m-%d %H:%M:%S'
            )
    
    def debug(self, message: str, **kwargs):
        """记录调试信息"""
        self.logger.debug(message, **kwargs)
    
    def info(self, message: str, **kwargs):
        """记录信息"""
        self.logger.info(message, **kwargs)
    
    def warning(self, message: str, **kwargs):
        """记录警告"""
        self.logger.warning(message, **kwargs)
    
    def error(self, message: str, **kwargs):
        """记录错误"""
        self.logger.error(message, **kwargs)
    
    def critical(self, message: str, **kwargs):
        """记录严重错误"""
        self.logger.critical(message, **kwargs)
    
    def log_operation(self, operation: str, status: str, details: Optional[Dict] = None):
        """记录操作日志"""
        message = f"操作: {operation} - 状态: {status}"
        if details:
            message += f" - 详情: {json.dumps(details, ensure_ascii=False)}"
        
        if status.lower() in ['success', 'completed', '成功', '完成']:
            self.info(message)
        elif status.lower() in ['warning', 'partial', '警告', '部分']:
            self.warning(message)
        else:
            self.error(message)
    
    def log_test_result(self, test_name: str, result: bool, details: Optional[str] = None):
        """记录测试结果"""
        status = "✅ 通过" if result else "❌ 失败"
        message = f"测试: {test_name} - {status}"
        if details:
            message += f" - {details}"
        
        if result:
            self.info(message)
        else:
            self.error(message)
    
    def log_system_info(self, info: Dict[str, Any]):
        """记录系统信息"""
        self.info(f"系统信息: {json.dumps(info, ensure_ascii=False, indent=2)}")
    
    def log_security_event(self, event_type: str, description: str, severity: str = "info"):
        """记录安全事件"""
        message = f"安全事件 [{event_type}]: {description}"
        
        if severity.lower() == "critical":
            self.critical(message)
        elif severity.lower() == "error":
            self.error(message)
        elif severity.lower() == "warning":
            self.warning(message)
        else:
            self.info(message)
    
    def setup_log_rotation(self, max_bytes: int = 10*1024*1024, backup_count: int = 5):
        """
        设置日志轮转
        
        Args:
            max_bytes: 单个日志文件最大字节数 (默认10MB)
            backup_count: 保留的备份文件数量 (默认5个)
        """
        if not self.enable_file or not self.log_file_path:
            return
        
        # 移除现有的文件处理器
        for handler in self.logger.handlers[:]:
            if isinstance(handler, logging.FileHandler):
                self.logger.removeHandler(handler)
                handler.close()
        
        # 添加轮转文件处理器
        rotating_handler = logging.handlers.RotatingFileHandler(
            self.log_file_path,
            maxBytes=max_bytes,
            backupCount=backup_count,
            encoding='utf-8'
        )
        
        # 设置格式
        if self.log_format == LogFormat.JSON.value:
            rotating_handler.setFormatter(JsonFormatter())
        elif self.log_format == LogFormat.EMOJI.value:
            rotating_handler.setFormatter(EmojiFormatter(self.EMOJI_FORMAT))
        else:
            rotating_handler.setFormatter(logging.Formatter(self.FORMATS[self.log_format]))
        
        self.logger.addHandler(rotating_handler)
        self.info("日志轮转已启用", max_bytes=max_bytes, backup_count=backup_count)
    
    def clean_old_logs(self, days_to_keep: int = 7):
        """
        清理旧日志文件
        
        Args:
            days_to_keep: 保留的天数 (默认7天)
        """
        if not self.log_dir:
            return
        
        cutoff_time = time.time() - (days_to_keep * 24 * 60 * 60)
        cleaned_count = 0
        
        try:
            # 查找所有日志文件
            log_patterns = [
                os.path.join(self.log_dir, "*.log"),
                os.path.join(self.log_dir, "*.log.*"),
                os.path.join(self.log_dir, "*.json"),
            ]
            
            for pattern in log_patterns:
                for log_file in glob.glob(pattern):
                    try:
                        if os.path.getmtime(log_file) < cutoff_time:
                            os.remove(log_file)
                            cleaned_count += 1
                    except (OSError, IOError) as e:
                        self.warning(f"无法删除日志文件 {log_file}: {e}")
            
            if cleaned_count > 0:
                self.info(f"清理了 {cleaned_count} 个旧日志文件")
            
        except Exception as e:
            self.error(f"清理旧日志文件时出错: {e}")
    
    def get_log_statistics(self) -> Dict[str, Any]:
        """
        获取日志统计信息
        
        Returns:
            包含日志统计信息的字典
        """
        stats = {
            'log_dir': self.log_dir,
            'log_file': self.log_file_path,
            'total_files': 0,
            'total_size_mb': 0,
            'oldest_file': None,
            'newest_file': None,
            'files': []
        }
        
        if not self.log_dir or not os.path.exists(self.log_dir):
            return stats
        
        try:
            log_files = []
            for pattern in ["*.log", "*.log.*", "*.json"]:
                log_files.extend(glob.glob(os.path.join(self.log_dir, pattern)))
            
            if not log_files:
                return stats
            
            total_size = 0
            oldest_time = float('inf')
            newest_time = 0
            
            for log_file in log_files:
                try:
                    stat = os.stat(log_file)
                    size_mb = stat.st_size / (1024 * 1024)
                    mtime = stat.st_mtime
                    
                    total_size += size_mb
                    oldest_time = min(oldest_time, mtime)
                    newest_time = max(newest_time, mtime)
                    
                    stats['files'].append({
                        'name': os.path.basename(log_file),
                        'size_mb': round(size_mb, 2),
                        'modified': datetime.fromtimestamp(mtime).isoformat()
                    })
                    
                except (OSError, IOError):
                    continue
            
            stats['total_files'] = len(log_files)
            stats['total_size_mb'] = round(total_size, 2)
            
            if oldest_time != float('inf'):
                stats['oldest_file'] = datetime.fromtimestamp(oldest_time).isoformat()
            if newest_time > 0:
                stats['newest_file'] = datetime.fromtimestamp(newest_time).isoformat()
            
        except Exception as e:
            self.error(f"获取日志统计信息时出错: {e}")
        
        return stats
    



class JsonFormatter(logging.Formatter):
    """JSON格式化器"""
    
    def format(self, record):
        log_data = {
            'timestamp': datetime.fromtimestamp(record.created).isoformat(),
            'level': record.levelname,
            'logger': record.name,
            'module': record.module,
            'function': record.funcName,
            'line': record.lineno,
            'message': record.getMessage()
        }
        
        if hasattr(record, 'exc_info') and record.exc_info:
            log_data['exception'] = self.formatException(record.exc_info)
        
        return json.dumps(log_data, ensure_ascii=False)


class EmojiFormatter(logging.Formatter):
    """Emoji格式化器"""
    
    def format(self, record):
        # 添加emoji到记录中
        record.emoji = UnifiedLogger.EMOJI_MAP.get(record.levelname, '📝')
        return super().format(record)


def get_logger(name: str = "privilege_ma", 
               config: Optional[Dict[str, Any]] = None) -> UnifiedLogger:
    """
    获取统一日志记录器实例
    
    Args:
        name: 日志记录器名称
        config: 配置字典
    
    Returns:
        UnifiedLogger实例
    """
    if config is None:
        config = {}
    
    return UnifiedLogger(
        name=name,
        log_level=LogLevel(config.get('log_level', LogLevel.INFO.value)),
        log_format=LogFormat(config.get('log_format', LogFormat.DETAILED.value)),
        log_dir=config.get('log_dir'),
        enable_console=config.get('enable_console', True),
        enable_file=config.get('enable_file', True),
        enable_rotation=config.get('enable_rotation', True),
        max_bytes=config.get('max_bytes', 10 * 1024 * 1024),
        backup_count=config.get('backup_count', 5),
        session_id=config.get('session_id')
    )


# 全局日志记录器实例
_global_logger = None


def setup_global_logger(config: Optional[Dict[str, Any]] = None) -> UnifiedLogger:
    """设置全局日志记录器"""
    global _global_logger
    _global_logger = get_logger("privilege_ma_global", config)
    return _global_logger


def get_global_logger() -> Optional[UnifiedLogger]:
    """获取全局日志记录器"""
    return _global_logger


# 便捷函数
def debug(message: str, **kwargs):
    """全局调试日志"""
    if _global_logger:
        _global_logger.debug(message, **kwargs)


def info(message: str, **kwargs):
    """全局信息日志"""
    if _global_logger:
        _global_logger.info(message, **kwargs)


def warning(message: str, **kwargs):
    """全局警告日志"""
    if _global_logger:
        _global_logger.warning(message, **kwargs)


def error(message: str, **kwargs):
    """全局错误日志"""
    if _global_logger:
        _global_logger.error(message, **kwargs)


def critical(message: str, **kwargs):
    """全局严重错误日志"""
    if _global_logger:
        _global_logger.critical(message, **kwargs)


if __name__ == "__main__":
    # 测试示例
    logger = get_logger("test_logger", {
        'log_level': LogLevel.DEBUG.value,
        'log_format': LogFormat.EMOJI.value,
        'log_dir': '/tmp/test_logs'
    })
    
    logger.info("🚀 统一日志系统测试开始")
    logger.debug("调试信息测试")
    logger.warning("警告信息测试")
    logger.error("错误信息测试")
    
    logger.log_operation("测试操作", "成功", {"参数": "测试值"})
    logger.log_test_result("示例测试", True, "测试通过")
    logger.log_security_event("登录尝试", "用户root登录成功", "info")
    
    print("日志统计:", json.dumps(logger.get_log_stats(), ensure_ascii=False, indent=2))